package com.onpositive.realmview.queryeditor.actions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.IStructuredSelection;

import com.onpositive.realmview.IRealmView;
import com.onpositive.realmview.model.filtering.BasicValueFilter;
import com.onpositive.realmview.model.filtering.IUIFilter;
import com.onpositive.realmview.queryeditor.GroupNode;
import com.onpositive.realmview.queryeditor.QueryEditorPart;
import com.onpositive.realmview.queryeditor.QueryEditorPart.FilterOperationUndoable;
import com.onpositive.semantic.model.api.undo.support.UndoRedoSupport;
import com.onpositive.semantic.model.realm.IModifiableRealm;

public class FilterBySelectionAction extends Action
{

	protected final IStructuredSelection selection;
	protected final IRealmView query;
	protected final QueryEditorPart part;

	public FilterBySelectionAction(IStructuredSelection selection, IRealmView query, QueryEditorPart part)
	{
		this.selection = selection;
		this.query = query;
		this.part = part;
	}
	
	
	public void run()
	{
		
		HashSet<IUIFilter> newFilters = new HashSet<IUIFilter>();
		Object[] elements = selection.toArray();
		for (int i = 0; i < elements.length; i++)
		{
			if (elements[i] instanceof GroupNode)
			{
				Collection<IUIFilter> filters = ((GroupNode) elements[i]).toFilters();
				newFilters.addAll(filters);
			}
		}
		final List<IUIFilter> filtersList = optimizeNewFilters(newFilters);
		FilterOperationUndoable filterOperationUndoable = part.new FilterOperationUndoable() {
			
			@Override
			public Object execute() {
				query.filters().add(filtersList);
				part.refreshViewer();
				return Status.OK_STATUS;
			}

			@Override
			public Object undo() {
				query.filters().remove(filtersList);
				part.refreshViewer();
				return Status.OK_STATUS;
			}
		};			
		UndoRedoSupport.getUndoRedoChangeManager().execute(filterOperationUndoable);		
	}

	/**
	 * Perform new filter additions with removing old filters for same property 
	 * @param newFilters
	 * @return 
	 */
	protected List<IUIFilter> optimizeNewFilters(HashSet<IUIFilter> newFilters)
	{
		
		List<IUIFilter> toRemove = new ArrayList<IUIFilter>();
		List<IUIFilter> optimizedFiltersList = new ArrayList<IUIFilter>(newFilters); //First, optimize new filters 
		for (int i = 0; i < optimizedFiltersList.size(); i++)
		{
			IUIFilter filter = optimizedFiltersList.get(i);
			if (!toRemove.contains(filter) && filter instanceof BasicValueFilter)
			{
				for (int j = i + 1; j < optimizedFiltersList.size(); j++)
				{
					
					IUIFilter current = optimizedFiltersList.get(j);
					if (current instanceof BasicValueFilter && //If we are BasicValueFilter instance and have a same grouping property as current...
						!toRemove.contains(current) && 
						current.getProperty().equals(filter.getProperty()))
					{
						toRemove.add(current);//... add our values to current filter and mark us as removed
						Set<Object> additionalValues = ((BasicValueFilter)current).getCurrentSelection();
						for (Iterator<Object> iterator = additionalValues.iterator(); iterator.hasNext();) 
						{
							Object value = (Object) iterator.next();
							((BasicValueFilter)filter).addValue(value);	
						}
						
					}
				}
			}
		}
		optimizedFiltersList.removeAll(toRemove);
		
		IModifiableRealm<IUIFilter> filters = query.filters(); //Second, delete all old filters for same props
		toRemove = new ArrayList<IUIFilter>();
		for (Iterator<IUIFilter> iterator = optimizedFiltersList.iterator(); iterator.hasNext();)
		{
			IUIFilter filter = (IUIFilter) iterator.next();
			for (Iterator<IUIFilter> iterator2 = filters.iterator(); iterator2.hasNext();)
			{
				IUIFilter oldFilter = (IUIFilter) iterator2.next();
				if (oldFilter.getProperty().equals(filter.getProperty()))
					toRemove.add(oldFilter);
			}
		}
		for (Iterator<IUIFilter> iterator = toRemove.iterator(); iterator.hasNext();)
		{
			IUIFilter removedFilter = (IUIFilter) iterator.next();
			filters.remove(removedFilter);	
		}
		
		return optimizedFiltersList;
	}

}
